﻿using System;
using System.Linq;
using System.Threading.Tasks;
using SDCloudSolution.SDCloud.BusinessLayer.Model.Interfaces;
using SDCloudSolution.SDCloud.BusinessLayer.ModelData.Interfaces;
using SDCloudSolution.SDCloud.Entities.Models.Data;
using SDCloudSolution.SDCloud.Web.Infrastructure.Interfaces;
using SDCloudSolution.SDCloud.Web.Models.ResultData;

namespace SDCloudSolution.SDCloud.Web.Infrastructure
{
    public class ModelResultViewModelProvider : IModelResultViewModelProvider
    {
        private readonly IModelRunComponent _modelRunComponent;
        private readonly IModelExecutionResultComponent _modelExecutionResultComponent;

        public ModelResultViewModelProvider(IModelRunComponent modelRunComponent, IModelExecutionResultComponent modelExecutionResultComponent)
        {
            _modelRunComponent = modelRunComponent;
            _modelExecutionResultComponent = modelExecutionResultComponent;
        }

        public async Task<ModelResultDataViewModel> GetModelResultDataAsync(int modelRunId)
        {
            var modelRunEntity = await _modelRunComponent.GetByIdAsync(modelRunId);

            if (modelRunEntity == null)
            {
                throw new UnauthorizedAccessException();
            }

            // TODO Add permission check to model access

            var result = await _modelExecutionResultComponent.GetResultsDataByModelExecutionId(modelRunId);
            if (result == null)
            {
                return null;
            }

            return ConvertToViewModel(result);
        }

        public async Task<ModelResultDataViewModel> GetModelResultDataAsync(int modelRunId, int framesSkipCount, int framesLimitCount)
        {
            var modelRunEntity = await _modelRunComponent.GetByIdAsync(modelRunId);
            if (modelRunEntity == null)
            {
                throw new UnauthorizedAccessException();
            }

            // TODO Add permission check to model access

            var result = await _modelExecutionResultComponent.GetResultsDataByModelExecutionIdAsync(modelRunId, framesSkipCount, framesLimitCount);
            if (result == null)
            {
                return null;
            }

            return ConvertToViewModel(result);
        }

        public async Task<ModelResultDataViewModel> GetModelResultDataAsync(int modelRunId, double? timeStart, double? timeEnd)
        {
            var modelRunEntity = await _modelRunComponent.GetByIdAsync(modelRunId);
            if (modelRunEntity == null)
            {
                throw new UnauthorizedAccessException();
            }

            // TODO Add permission check to model access

            var result = timeStart.HasValue || timeEnd.HasValue
                ? await _modelExecutionResultComponent.GetResultsDataByModelExecutionIdWithTimeFilter(modelRunId, timeStart, timeEnd)
                : await _modelExecutionResultComponent.GetResultsDataByModelExecutionId(modelRunId);

            if (result == null)
            {
                return null;
            }

            return ConvertToViewModel(result);
        }

        private static ModelResultDataViewModel ConvertToViewModel(ModelResultDataEntity result)
        {
            return new ModelResultDataViewModel
            {
                TimeStart = result.TimeStart,
                TimeEnd = result.TimeEnd,
                Columns = result.Columns.Select(column => new ModelResultColumnViewModel
                {
                    Id = column.Name,
                    DisplayName = column.DisplayName,
                    UnitName = column.UnitName
                }).ToList(),
                Frames = result.TimeFrames.Select(frame => new ModelResultTimeFrameViewModel
                {
                    Time = frame.Time,
                    TimeDelta = frame.TimeDelta,
                    Values = frame.Values
                }).ToList()
            };
        }
    }
}